/* init/main.c 
 * 
 * Copyright (C) 2021, 2022 intirain. 
 *
 * This file is part of evx. 
 * 
 * evx is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * evx is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with evx. If not, see <https://www.gnu.org/licenses/>
 */ 




#include <kernel/init.h>
#include <kernel/module.h>
#include <kernel/kernel.h>
#include <kernel/kmlog.h>
#include <kernel/mm.h>

#include <arch/archinfo.h>
#include <arch/asm.h>
#include <arch/mm.h>

#include <sys/types.h>


int init_state;
static int do_init_calls(void);

int __init init(void) {
	init_state = STATE_INIT_CALLS;

	do_init_calls();
	init_state = STATE_READY;

	return 0;
}

void *__init_data init_call_levels[] = {
	&_init_call_arch, &_einit_call_arch, 
	&_init_call_kernel, &_einit_call_kernel, 
	&_init_call_modules, &_einit_call_modules
};

/*
 * call hooks in those sections those defined with init_call_levels. 
 *
 * that when you use a module_init() macro, you add a new entry into 
 * that section. when bootstrap, we call them with no argument. if one 
 * of them returns a non-zero, kernel will halt and do nothing. 
 * */

typedef int (* __initcall_t) (void);


static int do_init_calls(void) {
	int error;
	int i;

	__archptr_t *start, *end;
	__archptr_t fn, *initcalls;

	for (i = 0; i < ARRAYSIZE(init_call_levels); i++) {
		start = init_call_levels[i];
		end = init_call_levels[++i];

		int ncalls = end - start;


		for (initcalls = start; ncalls; initcalls++, ncalls--) {
			fn = *initcalls;

			if (!fn) 
				break;

			if ((error = ((__initcall_t) fn)())) 
				return error;
		}
	}

	return 0;
}

